Skip to content

Feature/longer options display#14

Open
isidrolv wants to merge 20 commits intoin28minutes:masterfrom
isidrolv:feature/longer-options-display
Open

Feature/longer options display#14
isidrolv wants to merge 20 commits intoin28minutes:masterfrom
isidrolv:feature/longer-options-display

Conversation

@isidrolv
Copy link
Copy Markdown

@isidrolv isidrolv commented Apr 5, 2026

The purposo of this changes is to debug the questionarie database, and improve the way of how the questions are been displayed on the exam test program.

Copilot AI review requested due to automatic review settings April 5, 2026 21:22
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a Java quiz/questionnaire workflow (dataset + generation/fix scripts) and adds both console and Windows GUI quiz runners, aiming to improve how longer options/explanations are displayed while debugging the questionnaire data.

Changes:

  • Add Python quiz runners: a console app and a Windows Tkinter GUI with wrapped option display and optional charting.
  • Add scripts to generate and post-process Java questions into a JSON dataset, plus add config.yml for runtime settings.
  • Update Maven build config and formatting/ignore rules, and add additional documentation content.

Reviewed changes

Copilot reviewed 9 out of 15 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
src/main/java/com/in28minutes/java/arrays/ArrayExamples.java Formatting changes; spotted a ragged-array example bug and comment typos within touched lines.
pom.xml Adds explicit compiler plugin configuration alongside existing pluginManagement.
java_quiz_win.py New Tkinter GUI quiz app with wrapped radio button options and config loading.
java_quiz_console.py New console quiz runner with YAML config support and plotting.
generate_java_questions.py New generator from readme.md to data/java-questions.json.
fix_truncated_options.py New script to repair truncated correct-answer options using explanation text.
data/java-questions.json Adds the generated Java question bank used by quiz apps.
config.yml Adds runtime configuration (fonts/window/max_questions/pass_threshold).
code-samples.md Adds a large React coding-exercises addendum (appears unrelated to Java quiz changes).
.gitignore Adds .idea/ ignore.
_inspect.py Adds a local inspection/debug helper for the JSON dataset.
__pycache__/java_quiz_win.cpython-312.pyc Adds compiled Python bytecode (should not be committed).
__pycache__/java_quiz_console.cpython-312.pyc Adds compiled Python bytecode (should not be committed).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +105 to +108
matrixA[0] = new int[4];
matrixA[0] = new int[5];

// Above matrix has 2 rows 3 columns.
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ragged 2D array setup overwrites matrixA[0] three times, so only the last allocation survives. If the intent is to create multiple rows of different lengths, these should likely be matrixA[0], matrixA[1], matrixA[2] (or adjust the indices to match the desired shape).

Suggested change
matrixA[0] = new int[4];
matrixA[0] = new int[5];
// Above matrix has 2 rows 3 columns.
matrixA[1] = new int[4];
matrixA[2] = new int[5];
// Above matrix has 3 rows with different column sizes.

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +31
<configuration>
<source>8</source>
<target>8</target>
</configuration>
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This adds a second maven-compiler-plugin configuration in <build><plugins> that duplicates (and slightly diverges from) the existing config in <pluginManagement> (1.8 vs 8). Consider keeping the compiler settings in one place (either rely on pluginManagement and reference the plugin here without repeating <configuration>, or unify the values) to avoid future drift.

Suggested change
<configuration>
<source>8</source>
<target>8</target>
</configuration>

Copilot uses AI. Check for mistakes.
Comment on lines +156 to +160
# Top frame: title and progress
top_frame = ttk.Frame(self, padding=10)
top_frame.pack(side=tk.TOP, fill=tk.X)

self.title_label = ttk.Label(top_frame, text=TEST_TITLE, font=self.font_title)
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TEST_TITLE is assigned inside __init__ without declaring it global, so this creates a local variable and does not update the module-level TEST_TITLE that create_widgets() uses. This can cause the window title and the title label to get out of sync. Prefer storing the title on self (e.g., self.test_title) or declare global TEST_TITLE before assigning.

Suggested change
# Top frame: title and progress
top_frame = ttk.Frame(self, padding=10)
top_frame.pack(side=tk.TOP, fill=tk.X)
self.title_label = ttk.Label(top_frame, text=TEST_TITLE, font=self.font_title)
# Keep the title on the instance so widget creation does not depend
# on a module-level name that may not have been updated.
self.test_title = getattr(self, 'test_title', TEST_TITLE)
# Top frame: title and progress
top_frame = ttk.Frame(self, padding=10)
top_frame.pack(side=tk.TOP, fill=tk.X)
self.title_label = ttk.Label(top_frame, text=self.test_title, font=self.font_title)

Copilot uses AI. Check for mistakes.
aprobado = porcentaje >= PASS_THRESHOLD
msg = (
f"Respuestas correctas: {self.correct_count}/{self.total} ({porcentaje*100:.1f}%)\n\n" +
("🎉 ¡Aprobaste el test de React!" if aprobado else "❌ No aprobaste. ¡Sigue practicando!")
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pass/fail message says "React" even though this is the Java quiz app. This looks like a copy/paste error and will confuse users; update it to refer to Java (or to TEST_TITLE/the configured title).

Suggested change
("🎉 ¡Aprobaste el test de React!" if aprobado else "❌ No aprobaste. ¡Sigue practicando!")
(f"🎉 ¡Aprobaste {TEST_TITLE}!" if aprobado else f"❌ No aprobaste {TEST_TITLE}. ¡Sigue practicando!")

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +5
import json
import random
import os
import matplotlib.pyplot as plt

Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

matplotlib is imported unconditionally. If the environment running the console quiz doesn't have matplotlib installed, the script will crash at import time. Consider making this optional (same approach as java_quiz_win.py) or providing a no-plot fallback.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +15

# **Addendum: 10 coding challenge exercises**


Each exercise includes:

* **Task description**
* **Starting code sample (incomplete or incorrect)**
* **Final expected solution**

---

# 1.- Counter Component (useState)

**Task:** Create a simple counter with increment and decrement buttons.
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file adds a large set of React coding exercises, which doesn’t appear to relate to the PR goal of debugging/improving the Java questionnaire/quiz display. If this is not intentionally part of the quiz feature, consider moving it to a more appropriate location or removing it to keep the PR focused.

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +29
def ends_cleanly(text: str) -> bool:
"""Return True if text ends with sentence-terminal punctuation."""
t = text.strip()
return bool(t) and t[-1] in ".!?:"


def trim_to_sentence(text: str) -> str:
"""Return text trimmed at the last sentence-ending character (. ! ?)."""
t = text.strip()
if not t:
return t
if t[-1] in ".!?":
return t
for i in range(len(t) - 1, 0, -1):
if t[i] in ".!?":
return t[: i + 1]
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ends_cleanly() treats ':' as sentence-terminal punctuation, but trim_to_sentence() only treats '.!?' as sentence endings and the docstrings also suggest sentence endings. Either remove ':' from ends_cleanly() or update trim_to_sentence()/docstrings so the rules are consistent.

Copilot uses AI. Check for mistakes.
Comment on lines +69 to +106
if os.path.exists(CONFIG_FILE):
try:
if YAML_AVAILABLE:
with open(CONFIG_FILE, 'r', encoding='utf-8') as f:
data = yaml.safe_load(f) or {}
else:
# Very simple fallback parser: supports only top-level key: value numbers/strings
data = {}
with open(CONFIG_FILE, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if not line or line.startswith('#') or ':' not in line:
continue
key, val = line.split(':', 1)
key = key.strip()
val = val.strip().strip('"\'')
# try to cast number
try:
if '.' in val:
cast_val = float(val)
else:
cast_val = int(val)
data[key] = cast_val
except Exception:
data[key] = val
# Merge
if isinstance(data, dict):
if 'fonts' in data and isinstance(data['fonts'], dict):
cfg['fonts'].update({k: v for k, v in data['fonts'].items() if v is not None})
if 'window' in data and isinstance(data['window'], dict):
cfg['window'].update({k: v for k, v in data['window'].items() if v is not None})
if 'font_scale' in data and data['font_scale'] is not None:
cfg['font_scale'] = float(data['font_scale'])
if 'max_questions' in data and data['max_questions'] is not None:
cfg['max_questions'] = int(data['max_questions'])
if 'pass_threshold' in data and data['pass_threshold'] is not None:
cfg['pass_threshold'] = float(data['pass_threshold'])
except Exception:
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If PyYAML isn't installed, the fallback parser only supports top-level key: value pairs, but config.yml uses nested mappings (fonts, window). In that case, most of the config will silently not apply. Consider either adding an explicit dependency on PyYAML (so nested config always works) or enhancing the fallback parsing / surfacing a warning when nested keys are ignored.

Copilot uses AI. Check for mistakes.

// new Arrays are alway initialized with default values
System.out.println(marks2[0]);// 0
// new Arrays are alway initialized with default values
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in comment: "alway" → "always".

Suggested change
// new Arrays are alway initialized with default values
// new Arrays are always initialized with default values

Copilot uses AI. Check for mistakes.
// COMPILE ERROR!!
// int marks4[] = {10,15.0}; //10 is int 15.0 is float

// Cross assigment of primitive arrays is ILLEGAL
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in comment: "assigment" → "assignment".

Suggested change
// Cross assigment of primitive arrays is ILLEGAL
// Cross assignment of primitive arrays is ILLEGAL

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants